﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace BioCyber_Infection.Class
{
    class Network
    {
        #region Begin of Declaration

        Game game;
        public static NetworkSession networkSession;
        private bool isPlayerHost;

        private GameWindow window;
        private ContentManager content;

        //variável controladora que verifica se a sessão da Live foi aberta
        public bool isComponentRunning;

        //Variável controladora da quantidade máxima de jogadores no jogo 
        private int maxGamers = 4;
        private int maxLocalGamers = 4;

        #endregion

        #region Constructor
        public Network(Game game,ContentManager content,GameWindow gameWindow)
        {
            this.window = gameWindow;
            this.game = game;
            this.content = content;
        }
        #endregion


        /// <Live cmoponent Initialization>
        /// Inicialização do componente da Live (aquela janelinha da live e blah blah blah)
        /// </summary>
        #region Live Session Initialization
        private void StartLiveSession()
        {
            this.game.Components.Add(new GamerServicesComponent(this.game));
            this.isComponentRunning = true;
        }
        #endregion


        /// <UpdateMethod...>
        /// Método UPDATE da classe Network
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="currentStage"></param>
        #region Update
        public void Update(GameTime gameTime,BioCyber_Infection.Class.Screens.Stagees.Stagee currentStage)
        {
            if (networkSession == null)
            {
                //Se não houver Sessão alguma disponível, Não há nada que se possa fazer além de Atualizar o Menu.
                #region Update Menu Screen

                if (game.IsActive)
                {
                    //Engine.gamepad = GamePad.GetState(networkSession.LocalGamers[0].SignedInGamer.PlayerIndex);
                    if (this.game.Components.Count == 0)
                    {
                        //Se não houver jogo algum sendo rodado, Não poderemos prosseguir.
                        StartLiveSession();
                        Guide.ShowSignIn(1, false);
                    }

                    else if (Engine.isPressed(Keys.A, Buttons.A))
                    {
                        //this.isPlayerHost = true;
                        if (Engine.currentState != Engine.gameState.WAITROOM)
                        {
                            CreateSession();
                        }
                    }
                    else if (Engine.isPressed(Keys.B, Buttons.B))
                    {
                        //Join Session
                        //this.isPlayerHost = false;
                        if (Engine.currentState != Engine.gameState.WAITROOM)
                        {
                            joinSeSsion();
                        }
                    }
                } 
            } 
                #endregion
                
            else
            {
                //Se houver alguma sessão disponível, Atualizaremos os dados desta sessão.
                #region Update Network Session
                try
                {
                    currentStage.Update(gameTime);

                    Network.networkSession.Update();
                }

                catch (Exception e)
                {
                    throw e;
                }
                #endregion
            }
        }
        #endregion

        //Join session, create session etc...
        #region About Session

        /// <Creating a session...>
        /// Método utilizado para criar uma nova sessão
        /// </summary>
        private void CreateSession()
        {
            try
            {
                //Cria uma sessão com o tipo Systemlink. (vide tutorial no grupo do facebook para a explicação do método).
                networkSession = NetworkSession.Create(NetworkSessionType.SystemLink, this.maxLocalGamers, this.maxGamers);
                
                //Invoca a sessão toda vez que um player entra/cria no/o jogo(Vide sumário do Método)
                InvokeSessionEvents();

                //Engine.currentState = Engine.gameState.WAITROOM;
                Engine.currentState = Engine.gameState.STAGE1;
            }
            catch(Exception e)
            {
                throw e;
            }
        }

        /// <Joining Session....>
        /// Método utilizado para Joinar numa sessão já existente
        /// </summary>
        private void joinSeSsion()
        {
            try
            {
                //Esta rotina representa a busca por uma sessão já existente
                using (AvailableNetworkSessionCollection avaliableNetWorkSession =
                    NetworkSession.Find(NetworkSessionType.SystemLink, this.maxLocalGamers, null))
                {
                    if (avaliableNetWorkSession.Count == 0)
                    {
                        //Exibir uma mensagem de erro
                        return;
                    }
                    
                    networkSession = NetworkSession.Join(avaliableNetWorkSession[0]);

                    //Invoca a sessão toda vez que um player entra/cria no/o jogo(Vide sumário do Método)
                    InvokeSessionEvents();

                    
                    //Engine.currentState = Engine.gameState.WAITROOM;
                    Engine.currentState = Engine.gameState.STAGE1;
                    
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <A new player has joined the Session>
        /// Toda vez que um novo player se conectar a uma sessão, será criado
        /// um index e atribuido a um novo Jogador. Tal index será passado e
        /// atribuído ao novo Jogador
        /// </summary>
        private void GamerHasJoined(object sender, GamerJoinedEventArgs e)
        {
            //Índex necessário para a movimentação do player e afins.
            int gamerIndex = networkSession.AllGamers.IndexOf(e.Gamer);
            
            //atribui uma tag ao jogador que acabou de Joinar na sessão que advém do index do jogador que acabou de Joinar(e.Gamer);
            e.Gamer.Tag = new Player(gamerIndex,this.content);
        }

        /// <The player has left the Session>
        /// Método utilizado para finalizar a conexão local e sinalizar que o Player 
        /// deixou a sessão
        /// </summary>
        private void GamerHasLeft(object sender, NetworkSessionEndedEventArgs e)
        {
            networkSession.Dispose();
            networkSession = null;
        }

        /// <Invoking when...>
        /// Toda vez que tais Eventos forem engatilhados, este método será chamado, pois
        /// atualizará o Status de ir-e-vir dos players
        /// </summary>
        private void InvokeSessionEvents()
        {
            networkSession.GamerJoined += GamerHasJoined;
            networkSession.SessionEnded += GamerHasLeft;
        }

        /// <Sala de Espera - tá uma porcaria u.u>
        /// Em fase de teste
        /// </summary>
        /// <param name="spriteBatch"></param>
        public void DrawWaitRoom(SpriteBatch spriteBatch)
        {
            /*if (SignedInGamer.SignedInGamers.Count > 0)
            {
                if (networkSession.IsHost || networkSession.AllGamers.Count>1)
                    spriteBatch.DrawString(
                        content.Load<SpriteFont>("SpriteFont1"),
                        Network.networkSession.AllGamers[0].Gamertag + "'s Session... \n" +
                        "Waiting for other players \n" +
                        networkSession.AllGamers.Count.ToString() + "/4" +
                        "\n Press X to Start",
                        new Vector2(300, 300),
                        Color.White);

                else if (!this.isPlayerHost)
                    spriteBatch.DrawString(
                        content.Load<SpriteFont>("SpriteFont1"),
                        Network.networkSession.AllGamers[0].Gamertag + "'s Session... \n" +
                        "Waiting for other players \n" +
                        networkSession.AllGamers.Count.ToString() + "/4",
                        new Vector2(300, 300),
                        Color.White);
            }*/
        }

        #endregion


    }
}
